package call.count;

import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.PointcutAdvisor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.lang.reflect.Method;

/**
 * 功能：业务统计
 * 1、setBeanFactory 解析需要拦截的入口类
 * 2、getPointcut 动态拦截
 * 3、getAdvice 统计调用次数
 *
 * @author baitao20
 * @date 2024/2/18 11:48
 **/
public class CallCountBootStrap implements BeanFactoryAware, PointcutAdvisor {

    private final static Logger logger = LoggerFactory.getLogger(CallCountBootStrap.class);

    @Resource
    private CallCountHelper callCountHelper;

    @Value("${APP_NAME:未知}")
    private String SYSTEM_NAME;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        // todo unknow UMP
//        CallerInfo callerInfo = Profiler.registerInfo(CallCountConstant.UMP_CALLCOUNTBOOTSTRAP_SETBEANFACTORY, SYSTEM_NAME, false, true);
        try {
            if (beanFactory instanceof DefaultListableBeanFactory) {
                callCountHelper.beanFactory = (DefaultListableBeanFactory) beanFactory;
            }
            callCountHelper.checkIsIntercept();
            callCountHelper.analysisCallCountComponent();
            callCountHelper.timerPrint();
        } catch (Throwable e) {
//            Profiler.functionError(callerInfo);
            logger.error("[CALL_COUNT_LOG] CallCountBootStrap.setBeanFactory error:{}", e.getMessage(), e);
        } finally {
//            Profiler.registerInfoEnd(callerInfo);
        }
    }

    /**
     * 拦截器，统计调用次数
     * @return Advice
     */
    @Override
    public Advice getAdvice() {
        return (MethodInterceptor) invocation -> {
//            CallerInfo callerInfo = Profiler.registerInfo(CallCountConstant.UMP_CALLCOUNTBOOTSTRAP_GETADVICE, SYSTEM_NAME, false, true);
            try {
                callCountHelper.adviceInvocationCallCount(invocation);
            } catch (Throwable e) {
//                Profiler.functionError(callerInfo);
                logger.error("[CALL_COUNT_LOG] CallCountBootStrap.getAdvice error:{}", e.getMessage(), e);
            } finally {
//                Profiler.registerInfoEnd(callerInfo);
            }
            return invocation.proceed();
        };
    }

    @Override
    public boolean isPerInstance() {
        return true;
    }

    @Override
    public Pointcut getPointcut() {
        return new Pointcut() {
            @Override
            public MethodMatcher getMethodMatcher() {
                return new MethodMatcher() {
                    @Override
                    public boolean matches(Method method, Class<?> targetClass, Object... args) {
                        return false;
                    }

                    @Override
                    public boolean matches(Method method, Class<?> targetClass) {
//                        CallerInfo callerInfo = Profiler.registerInfo(CallCountConstant.UMP_CALLCOUNTBOOTSTRAP_GETPOINTCUT, SYSTEM_NAME, false, true);
                        try {
                            return callCountHelper.pointcutMatches(method, targetClass);
                        } catch (Throwable e) {
//                            Profiler.functionError(callerInfo);
                            logger.error("[CALL_COUNT_LOG] CallCountBootStrap.getPointcut matches error:{}", e.getMessage(), e);
                            return false;
                        } finally {
//                            Profiler.registerInfoEnd(callerInfo);
                        }
                    }

                    @Override
                    public boolean isRuntime() {
                        return false;
                    }
                };
            }

            // 拦截所有类
            @Override
            public ClassFilter getClassFilter() {
                return ClassFilter.TRUE;
            }
        };
    }

    @PostConstruct
    public void init() {
        try {
            callCountHelper.resetDataPacket();
            logger.info("[CALL_COUNT_LOG] CallCountBootStrap init resetDataPacket success");
        } catch (Throwable e) {
            logger.error("[CALL_COUNT_LOG] CallCountBootStrap init resetDataPacket error:{}", e.getMessage(), e);
        }
    }

    @PreDestroy
    public void destroy() {
        try {
            CallCountHelper.schedule.shutdown();
        } catch (Throwable e) {
            logger.error("[CALL_COUNT_LOG] CallCountBootStrap destroy schedule.shutdown error:{}", e.getMessage(), e);
        }
        try {
            callCountHelper.resultBroadcast();
        } catch (Throwable e) {
            logger.error("[CALL_COUNT_LOG] CallCountBootStrap destroy resultBroadcast error:{}", e.getMessage(), e);
        }
        logger.info("[CALL_COUNT_LOG] CallCountBootStrap destroy complete");
    }
}